package com.xjd.edu.toolkit.helper;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.xjd.edu.toolkit.exception.BlockingException;

import java.sql.SQLException;

/**
 * 异常工具类
 *
 * @author wangyu
 * @since 2023/2/8
 */
public class ExceptionHelper {

    /**
     * 展开异常，返回原始异常实例
     *
     * @param e 非空
     * @return
     */
    public static Throwable unwrap(Throwable e) {
        if (e == null) {
            return null;
        }
        Throwable unwrap = ExceptionUtil.unwrap(e);
        // 这里使用 for 循环而不是 while 循环是为了防止出现无限套娃的情况，即：最多回溯 16 层
        for (int i = 0; i < 16; i++) {
            if (unwrap.getCause() == null) {
                return unwrap;
            }
            unwrap = unwrap.getCause();
        }

        return unwrap;
    }

    /**
     * 判断异常是否是限流异常
     *
     * @param e 非空
     * @return
     */
    public static boolean isLimitException(Throwable e) {
        if (e == null) {
            return false;
        }

        final Throwable ue = unwrap(e);

        // 自定义阻塞异常（限流）
        if (ue instanceof BlockingException) {
            return true;
        }

        // 如果是 java.sql.SQLException 判断异常状态码
        if (ue instanceof SQLException) {
            final int code = ((SQLException) ue).getErrorCode();

            // MySQL 限流
            // RDS MySQL 5.6、RDS MySQL 5.7的实例和PolarDB MySQL 5.6的集群会返回1317错误（query execution was interrupted）
            // RDS MySQL 8.0 -> 7534
            // PolarDB MySQL 5.7 -> 3277
            // PolarDB MySQL 8.0 -> 7533
            if (code == 1317 || code == 7533 || code == 7534 || code == 3277) {
                return true;
            }
        }

        return false;
    }

}
